package com.uzhie.jt808;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by Coder on 2018/7/6.
 * 808 服务端
 */
public class JT808Server {

    private Logger logger = Logger.getLogger(this.getClass());
    private volatile boolean isRunning = false;

    private int port;
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private ServerBootstrap serverBootstrap;
    private ChannelInboundHandlerAdapter channelInboundHandlerAdapter;

    public void setPort(int port) {
        this.port = port;
    }

    public void setBossGroup(EventLoopGroup bossGroup) {
        this.bossGroup = bossGroup;
    }

    public void setWorkerGroup(EventLoopGroup workerGroup) {
        this.workerGroup = workerGroup;
    }

    public void setServerBootstrap(ServerBootstrap serverBootstrap) {
        this.serverBootstrap = serverBootstrap;
    }

    public void setChannelInboundHandlerAdapter(ChannelInboundHandlerAdapter channelInboundHandlerAdapter) {
        this.channelInboundHandlerAdapter = channelInboundHandlerAdapter;
    }

    /**
     * 初始化808服务
     */
    public void init() {
        logger.trace("加载 808 Service");
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                run808();
            }
        }, "JT808-Thread");
        thread.start();
    }

    /**
     * 容器退出时 停止808服务线程
     *
     * @throws InterruptedException
     */
    public void destroy() throws InterruptedException {
        logger.trace("停止 808 Service");
        stop();
    }

    private synchronized void run808() {
        try {
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            // 808 解码器
                            ch.pipeline().addLast(new JT808ByteDecoder(JT808Constant.SPLIT_SYMBOL));
                            // 808 编码器
                            ch.pipeline().addLast(new JT808ByteEncoder());
                            // 808 协议请求处理器
                            ch.pipeline().addLast(channelInboundHandlerAdapter);
                        }
                    });
            serverBootstrap.bind(port).sync();
            isRunning = true;
            logger.trace("JT808 TCP server is running on port " + port + " 808服务启动成功！");
        } catch (Exception e) {
            logger.trace("JT808 TCP server not running on port " + port + "启动808服务异常！" + e);
            stop();
        } finally {
            logger.trace("808服务启动完成！");
        }
    }

    private void stop() {
        try {
            if (isRunning) {
                bossGroup.shutdownGracefully().sync();
                workerGroup.shutdownGracefully().sync();
                isRunning = false;
                logger.trace("关闭 808 服务成功");
            } else {
                logger.trace("808 服务未启动！");
            }
        } catch (InterruptedException e) {
            logger.trace("关闭 808 服务失败！", e);
        } finally {
            logger.trace("关闭 808 服务完成！");
        }

    }

    public static void main(String[] args) throws Exception {
        ApplicationContext ct = new ClassPathXmlApplicationContext("classpath:spring-context.xml", "classpath:spring-redis.xml", "classpath:spring-ehcache.xml", "classpath:spring-jt808.xml");
    }
}
